package com.robot.service;

import com.google.common.collect.Lists;
import com.jayway.jsonpath.JsonPath;
import com.robot.clientfactory.ClientFactory;
import com.robot.clientfactory.ClientProcessor;
import com.robot.constant.BuildTestStatus;
import com.robot.constant.RunMode;
import com.robot.dao.*;
import com.robot.dto.RunTestContext;
import com.robot.model.*;
import com.robot.util.DateUtil;
import com.robot.util.ReportLogUtil;
import com.robot.vo.ReportLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * User: li
 * Date: 2019/11/24
 * Time: 16:57
 * PROJECT：robot
 * PACKAGE: com.robot
 *
 * @author:55324936@qq.com To change this template use File | Settings | File Templates.
 */
@Service
@Slf4j
public class RunTestService {

    @Autowired
    ClientFactory clientFactory;
    @Autowired
    BuildTestMapper buildTestMapper;
    @Autowired
    BuildTestCaseMapper buildTestCaseMapper;
    @Autowired
    BuildTestInterfaceMapper buildTestInterfaceMapper;
    @Autowired
    DubboService dubboService;
    @Autowired
    AssertService assertService;
    @Autowired
    DateUtil dateUtil;
    @Autowired
    TestPlanDetailMapper testPlanDetailMapper;
    @Autowired
    InterfaceMapper interfaceMapper;

    static Pattern elPattern = Pattern.compile("\\$\\{(.*?)\\}");

    /**
     * 执行测试
     **/
    public void runTest(RunTestContext runTestContext) {
        Integer buildTestId = runTestContext.getBuildTestDo().getId();
        ReportLogUtil reportLogUtil = new ReportLogUtil(buildTestId);
        reportLogUtil.writeSpan("开始初始化运行数据!");
        runTestContext.setReportLogUtil(reportLogUtil);
        BuildTestDo buildTestDo = buildTestMapper.buildTestById(buildTestId);
        reportLogUtil.writeSpan("初始化接口信息完成,运行接口数量:" + buildTestDo.getBuildTestInterfaceDoList().size());
        runTestContext.setBuildTestDo(buildTestDo);
        Integer runMode = buildTestDo.getRunMode();
        try {
            if (runMode.intValue() != RunMode.TESTPALNRUN) {
                reportLogUtil.writeSpan("当前运行模式:接口模式运行");
                this.runTestByBuild(runTestContext);
            } else {
                reportLogUtil.writeSpan("当前运行模式:测试计划模式运行");
                this.runTestSuite(runTestContext);
            }
        } finally {
            reportLogUtil.closeWriter();
        }

    }

    /**
     * 按照场景运行测试
     **/
    public void runTestSuite(RunTestContext runTestContext) {
        BuildTestDo buildTest = runTestContext.getBuildTestDo();
        Integer testPlanId = buildTest.getTestPlanId();
        TestPlanDetailDo testPlanDetailDoParam = new TestPlanDetailDo();
        testPlanDetailDoParam.setTestPlanId(testPlanId);
        List<TestPlanDetailDo> testPlanDetailDoList = testPlanDetailMapper.getTestPlanDetailByPlanId(testPlanDetailDoParam);
        Long startTime = System.currentTimeMillis();
        ReportLogUtil logFileUtil = runTestContext.getReportLogUtil();
        /**记录上次执行的用例信息**/
        BuildTestCaseDo lastBuildTestCase = null;
        try {
            for (TestPlanDetailDo testPlanDetailDo : testPlanDetailDoList) {
                String interfaceAliasName = testPlanDetailDo.getInterfaceAliasName();
                Protocol protocol = interfaceMapper.getProtocolById(testPlanDetailDo.getInterfaceId());
                String interfaceType = protocol.getInterfaceType();
                logFileUtil.writeSpan("初始化测试接口名称:[" + interfaceAliasName + "]完成,接口类型:[" + interfaceType + "]");
                if (null == protocol) {
                    logFileUtil.writeRedSpan("接口[" + interfaceAliasName + "],已经被删除停止运行");
                    continue;
                }
                /**获取执行引擎:http、dubbo**/
                ClientProcessor clientProcessor = clientFactory.getClient(protocol.getInterfaceType());
                BuildTestInterfaceDo buildTestInterface = new BuildTestInterfaceDo();
                BeanUtils.copyProperties(protocol, buildTestInterface);
                buildTestInterface.setBuildTestId(buildTest.getId());
                runTestContext.setBuildTestInterfaceDo(buildTestInterface);

                BuildTestCaseDo buildTestCase = new BuildTestCaseDo();
                BeanUtils.copyProperties(testPlanDetailDo, buildTestCase);
                buildTestCase.setBuildTestInterfaceId(protocol.getId());
                buildTestCase.setTestCaseName("场景用例");

                List<BuildTestCaseDo> buildTestCaseDoList = Lists.newArrayList();
                buildTestCaseDoList.add(buildTestCase);
                runTestContext.setBuildTestCaseDo(buildTestCase);
                String param = testPlanDetailDo.getParam();
                if (param.contains("${")) {
                    /**如果用例参数含有${符号的话，获取上一条用例的返回结果作为当前入参的内容**/
                    Matcher m = elPattern.matcher(param);
                    while (m.find()) {
                        String tempKey = m.group();
                        String expression = tempKey.substring(tempKey.indexOf("{") + 1, tempKey.indexOf("}"));
                        String actualResult = lastBuildTestCase.getActualResult();
                        try {
                            String value = JsonPath.read(actualResult, expression);
                            param = param.replace(tempKey, value);
                        } catch (Exception e) {
                            log.error("获取值异常", e);
                        }
                    }
                }
                buildTestCase.setParam(param);
                /**记录接口运行开始时间**/
                Long interfaceStartTime = System.currentTimeMillis();

                /**开始执行当前接口下的所有用例**/
                clientProcessor.runTest(runTestContext);
                /**记录接口运行结束时间**/
                Long interfaceEndTime = System.currentTimeMillis();
                assertService.assertResult(runTestContext);
                /**计算用例数量、通过率、执行时间**/
                runTestContext.calculation(buildTestCaseDoList);
                logFileUtil.writeSpan("接口[" + interfaceAliasName + "]运行完成,运行时长:" + (interfaceEndTime - interfaceStartTime) / 1000);
                lastBuildTestCase = runTestContext.getBuildTestCaseDo();
                buildTestInterface.setBuildTestId(buildTest.getId());
                /**更新运行的测试用例**/
                buildTestInterfaceMapper.addBuildTestInterface(runTestContext.getBuildTestInterfaceDo());
                List<BuildTestCaseDo> buildTestCaseDos =Lists.newArrayList();
                runTestContext.getBuildTestCaseDo().setBuildTestInterfaceId(runTestContext.getBuildTestInterfaceDo().getId());
                buildTestCaseDos.add(runTestContext.getBuildTestCaseDo());
                buildTestCaseMapper.addBuildTestCaseList(buildTestCaseDos);
                buildTestMapper.modifyBuildTest(runTestContext.getBuildTestDo());
            }
        } catch (Exception e) {
            log.error("执行计划异常", e);
            buildTest.setStatus(BuildTestStatus.ERROR);
            logFileUtil.writeRedSpan("执行计划异常:" + e);
        } finally {
            Long runTime = this.runTime(startTime);
            buildTest.setRunTime(runTime);
            buildTest.setRunStatus(BuildTestStatus.FINISH);
            buildTestMapper.modifyBuildTest(buildTest);
        }
    }

    /**
     * 按照临时构建运行
     **/
    private void runTestByBuild(RunTestContext runTestContext) {
        BuildTestDo buildTestDo = runTestContext.getBuildTestDo();
        buildTestDo.setStartTime(dateUtil.getCurrentTime());
        List<BuildTestInterfaceDo> buildTestInterfaceDoList = buildTestDo.getBuildTestInterfaceDoList();
        ReportLogUtil reportLogUtil = runTestContext.getReportLogUtil();
        Long startTime = System.currentTimeMillis();
        /**按照执行的接口拿出来信息**/
        buildTestDo.setRunStatus(BuildTestStatus.RUNNING);
        buildTestMapper.modifyBuildTest(buildTestDo);
        try {
            reportLogUtil.writeSpan("准备开始执行测试!");
            int flag = 0;
            for (BuildTestInterfaceDo buildTestInterfaceDo : buildTestInterfaceDoList) {
                String interfaceType = buildTestInterfaceDo.getInterfaceType();
                ClientProcessor clientProcessor = clientFactory.getClient(interfaceType);
                runTestContext.setBuildTestInterfaceDo(buildTestInterfaceDo);
                List<BuildTestCaseDo> buildTestCaseDoList = buildTestInterfaceDo.getBuildTestCaseDoList();
                reportLogUtil.writeSpan("当前执行的接口是:" + buildTestInterfaceDo.getInterfaceAliasName());
                for (BuildTestCaseDo buildTestCaseDo : buildTestCaseDoList) {
                    runTestContext.setBuildTestCaseDo(buildTestCaseDo);
                    /**我传给你各种参数，你返回给我一个结果(不同的车)就行了**/
                    clientProcessor.runTest(runTestContext);
                    assertService.assertResult(runTestContext);
                    Thread.sleep(2000);
//                    if(flag % 4 ==0){
//                        /**计算通过数据**/
//                        runTestContext.calculation(buildTestCaseDoList);
//                        /**通过率、用例总数、状态**/
//                        buildTestMapper.modifyBuildTest(buildTestDo);
//                    }
                }
                if (CollectionUtils.isEmpty(buildTestCaseDoList)) {
                    continue;
                }
                reportLogUtil.writeSpan("当前接口执行完成,接口是:" + buildTestInterfaceDo.getInterfaceAliasName());
                /**计算通过数据**/
                runTestContext.calculation(buildTestCaseDoList);
                /**更新运行的测试用例**/
                buildTestCaseMapper.modifyBuildTestCase(buildTestCaseDoList);
                /**每执行完成一个接口之后就去更新对应的信息**/
                buildTestInterfaceMapper.modifyBuildTestInterface(buildTestInterfaceDo);
                /**构建计划更新一次，因为页面上理论想要实时结果**/
                /**通过率、用例总数、状态**/
                Long runTime = this.runTime(startTime);
                buildTestDo.setRunTime(runTime);
                buildTestMapper.modifyBuildTest(buildTestDo);
            }
        } catch (Exception e) {
            log.error("执行计划异常", e);
            buildTestDo.setStatus(BuildTestStatus.ERROR);
        } finally {
            Long runTime = this.runTime(startTime);
            buildTestDo.setRunTime(runTime);
            buildTestDo.setRunStatus(BuildTestStatus.FINISH);
            buildTestMapper.modifyBuildTest(buildTestDo);
        }
    }

    private Long runTime(Long startTime) {
        Long endTime = System.currentTimeMillis();
        Long runTime = endTime - startTime;
        runTime = runTime / 1000;
        if (runTime == 0) {
            runTime = 1L;
        }
        return runTime;
    }

    /**
     * 获取执行过程中的日志内容
     *
     * @param buildTestId
     * @param lastTimeFileSize
     **/
    public ReportLog runLog(Integer buildTestId, Long lastTimeFileSize) {
        ReportLogUtil reportLogUtil = new ReportLogUtil();
        if (null != lastTimeFileSize) {
            return reportLogUtil.read(buildTestId, lastTimeFileSize);
        } else {
            lastTimeFileSize = 0L;
            return reportLogUtil.read(buildTestId, lastTimeFileSize);
        }
    }

    private void runTestByTestPlan() {

    }
}
